# class Reactangle():
#     def __init__(self):
#         print("I am Reactangle.__init__")
#
#     def introself(self):
#         print("I am Reactangle")

# class ShapeFactory():
#
#     def makeClass(self,clazz):
#         instance = clazz()
#         return instance


# shapeFactory = ShapeFactory()
# reactangle = shapeFactory.makeClass(clazz=Reactangle)
# reactangle.introself()

# 工厂模式：将实例化的过程统一交给第三方实例完成
# 看到这里，好像感觉工厂模式并没有带来什么大的改变

# 接下来我们修改一下Reactangle类
"""
'''
class Reactangle():
    dict_data = {};
    s1 = None
    s2 = None
    def __init__(self, dict_items=()):
        for key, value in dict_items:
            self.dict_data[key] = value
        self.s1 = self.dict_data['s1']
        self.s2 = self.dict_data['s2']


    def introself(self):
        print(self.s2)
'''

# shapeFactory = ShapeFactory()
# reactangle = shapeFactory.makeClass(clazz=Reactangle)
# reactangle.introself()
# 这样运行下去，我们会得到一个错误，str参数必须要给
# 我们必须要修改ShapeFactory，以便它能更好的扩展
'''
class ShapeFactory():
    def makeClass(self, clazz, **kwargs):
        return clazz(dict_items = kwargs.items())
        # if kwargs is not None:
        #     instance = clazz(kwargs.items())
        #     return instance
'''

# reactangle.introself()
# 这样我们可以解决这个问题了，但是我们的__init__函数有时候需要更为复杂的参数，那么我们就要用到魔术参数了
# 我们应该怎么做呢？

'''
shapeFactory = ShapeFactory()
reactangle = shapeFactory.makeClass(clazz=Reactangle,s2="S2", s1="S1")
reactangle.introself()
'''

# 这样虽然是可以实例化大多数类，但是这样的工厂仅仅有指定类的实例化能力，而没有选择能力
'''
换句话说，我们并不想在我们的业务代码里指定实例化哪个类，我们只想实现Shape这个功能，至于具体是哪一个Shape，
是Reactangle，还是Triangle我们并不想知道，我们希望具体的选择权交给config（配置文件），我们应该怎么做呢
'''
"""

# 第一步我们创建Reactangle和Triangle类

class Reactangle():
    s1 = None
    s2 = None
    def __init__(self, dict_params=()):
        self.s1 = dict_params['s1']
        self.s2 = dict_params['s2']
    def introself(self):
        print("I am Reactangle")

class Triangle():
    w = None
    h = None
    def __init__(self, dict_params=None):
        self.w = dict_params['w']
        self.h = dict_params['h']
    def introself(self):
        print("I am Triangle")
# 我们有了这两个类（设计图），我们可以建立工厂生产他们了
"""
class ShapeFactory():
    def makeClass(self, clazz, **kwargs):
        return clazz(dict_items = kwargs.items())
"""
# 等等我们还不能生产他们，我们还缺了一步选择
"""
class ShapeFactory():
    def makeClass(self,classNmae):
        if classNmae == "Reactangle":
            return Reactangle({"s1":"S1","s2":"S2"}.items())
        if classNmae == "Triangle":
            return Triangle({"w":"W","h":"H"}.items())

shapeFactory = ShapeFactory()
reactangle = shapeFactory.makeClass('Triangle')
reactangle.introself()
"""
# 这貌似可以解决我们想通过配置文件选择实例化的方式，但是这样如果有很多类可以选择，ShapeFactory将会有大量的
# 重复代码，想一想我们应该怎么解决这个问题
class ShapeFactory():
    def makeClass(self, clazz, params):
        return clazz(params)

# 现在我们在创建一个工人Worker，由它选择执行实例化的类


class ShapeWorker():
    # 这里我们创建一个dict_items来模拟配置文件
    dict_config = {
        "Reactangle": {"clazz": Reactangle, "params": {"s1": "S1", "s2": "S2"}},
        "Triangle": {"clazz": Triangle, "params": {"w": "W", "h": "h"}}
    }
    # dict_config = ([("className", "Reactangle"), ("clazz", Reactangle),])
    def selectInstance(self, className):
        selected = self.dict_config[className]
        shapeFactory = ShapeFactory()
        return shapeFactory.makeClass(clazz=selected['clazz'], params=selected['params'])

# shapeWorker = ShapeWorker()
# instance = shapeWorker.selectInstance('Reactangle')
# instance.introself()

"""
总结：OK,现在我们实现了通过配置文件保存我们实例化一个类所用的资源，我们自然也可以直接通过配置文件来选择
实例化的类
"""
class ShapeWorker():
    # 这里我们创建一个dict_items来模拟配置文件
    dict_config = {
        "SelectClass": {"clazz": Reactangle, "params": {"s1": "S1", "s2": "S2"}},
        # "Triangle": {"clazz": Triangle, "params": {"w": "W", "h": "h"}}
    }
    # dict_config = ([("className", "Reactangle"), ("clazz", Reactangle),])
    def selectInstance(self):
        selected = self.dict_config["SelectClass"]
        shapeFactory = ShapeFactory()
        return shapeFactory.makeClass(clazz=selected['clazz'], params=selected['params'])

shapeWorker = ShapeWorker()
instance = shapeWorker.selectInstance()
instance.introself()

"""
想一想，这对我们有什么意义：意义在于，我们可以通过实现一个ShapeWorker来创建一个具体的Shape（Reactangle，
Triangle or else）的实例，我们也可以通过一个ColorWorker来创建一个具体的Color（red，blue or else）实例
亦或是我们通过传参数（注入）的方式选择config文件，以实例化我们想要的类
"""
"""
总结：总的来说一句话，我需要一个形状，但我不知道是什么形状；我需要一个颜色，但我不知道是什么颜色，谁知道呢？
配置文件知道
"""


